iT邦幫忙

2022 iThome 鐵人賽

DAY 23
0
Modern Web

Angular牙起來系列 第 23

# Day23 【牙起來】 元件執行順序 & 生命週期 - Angular

  • 分享至 

  • xImage
  •  

Day23 【牙起來】 元件執行順序 & 生命週期 - Angular

再繼續往RxJS的道路之前,
先插播一則文章,回過頭來看Angular元件、服務、生命週期與執行的順序

constructor、ngOnInit

透過ng cli產出的元件,底下都會有以下兩個方法(Method)

  • constructor() Typescript的構建物件函式
  • ngOnInit() Angular元件初始化時執行

在初學階段,這兩者都可以視作元件初始化時做的事情
只要知道ngOnInit執行的時機點晚於constructor一些

因為constructor() Typescript層的東西
其中小括號內()是構建函式的Input參數(Parameter)
把這個物件所需要用到、所依賴的服務注入進來,提供給這整個物件使用(讓物件內的每個方法都可以取用到)

昨天看到的 HttpClient 是Angular內建的眾多服務(Service)之一,就是透過注入服務到元件中讓元件能使用該服務底下的方法。未來我們也會自行寫服務service.ts,注入到自己寫的元件中。

所以執行順序為,
先執行構建物件,等構建完畢之後才執行Angular元件初始化

  constructor() {
    console.log('==== constructor ====')
  }

  ngOnInit(): void {
    console.log('==== ngOnInit ====')
  }

生命週期、執行順序

除了以上兩種預設的方法之外,還有很多內建方法


export class AppComponent implements OnInit, OnDestroy, AfterViewInit {

  constructor() {
    console.log('==== constructor ====')
  }

  ngOnInit(): void {
    console.log('==== ngOnInit ====')
  }

  ngAfterViewInit(): void {
    console.log('==== ngAfterViewInit ====')
  }

  ngOnDestroy() {
    console.log('==== ngOnDestroy ====')
  }
}

這一行 implements OnInit, OnDestroy, AfterViewInit 實作介面
有加、沒加都不會對畫面產生影響

因為Javascript沒有interface,最終編譯都是相同結果
只是加了對程式碼風格較好,有助於IDE推斷介面型別

執行結果

  • constructor 構建一個物件首先執行的函式,在這裡引入物件所需用到的服務
  • ngOnInit 生命週期 元件初始化,進入此元件做的事情,此時畫面尚未生成完畢
  • ngAfterViewInit 生命週期 當畫面(View)渲染完畢才做的事

    例如抓取頁面上的某個節點,若在畫面出現之前執行的話會抓不到元素而變成undefined

  • ngOnDestroy 生命週期 離開、結束此元件時做的事情

    刷新頁面或離開頁面都不會觸發效果
    因為是這兩件事情主導權不在Angular手上,而是由瀏覽器銷毀
    在未來提及Rouing切換頁面元件時可以看到效果

以人類的生命週期來對應的話,分別是

  • 受精階段: constructor 建構胚胎卵,注入所需要的養分服務,以幫助未來成長
  • 胎兒階段: ngOnInit 元件在媽媽的肚子裡面長好了
  • 嬰兒階段: ngAfterViewInit 畫面生出來了,我們肉眼看的見四肢了
  • 死亡階段: destroy 生命離開肉體軀殼,被大自然回收了

巢狀結構的執行順序

我們在 appstore 兩個元件中,都分別印出以上四種狀態

修改 store.component.ts

...

export class StoreComponent implements OnInit, AfterViewInit, OnDestroy {

  constructor() {
    console.log('==== StoreComponent constructor ====')
  }

  ngOnInit(): void {
    console.log('==== StoreComponent ngOnInit ====')
  }

  ngAfterViewInit(): void {
    console.log('==== StoreComponent ngAfterViewInit ====')
  }

  ngOnDestroy(): void {
    console.log('==== StoreComponent ngOnDestroy ====')
  }
}

修改 app.component.ts

export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
  title = 'project03';

  constructor() {
    console.log('==== AppComponent constructor ====')
  }

  ngOnInit(): void {
    console.log('==== AppComponent ngOnInit ====')
  }

  ngAfterViewInit(): void {
    console.log('==== AppComponent ngAfterViewInit ====')
  }

  ngOnDestroy(): void {
    console.log('==== AppComponent ngOnDestroy ====')
  }

}

修改 app.component.html

<app-store></app-store>

結果畫面

可以看到巢狀的執行順序
先是App的建構,建構完畢跑進Store開始建構,接著開始Angular的生命週期,
APP開始初始化,等Store初始化好了、畫面都好了,最終APP的畫面才好。

加上服務的執行順序

透過ng cli建立一個名為svc的服務

> ng g s svc

修改svc.service.ts

import { Injectable, OnInit } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class SvcService implements OnInit{

  constructor() {
    console.log('SvcService constructor')
  }
  
}

接著分別在app.component.tsstore.component.ts
加上這一段試試看效果

  constructor(svc: SvcService) {
  }
  • 僅將svc: SvcService加在 app.component.ts 的結果

  • 僅將svc: SvcService加在 store.component.ts 的結果

由此可見,注入的服務是在Construct()的前一刻先被執行


服務(Service)沒有元件生命週期

服務(Service)沒有Angular生命週期
就算加了ngOnInit等方法,也不會有任何作用

Angular生命週期只有元件(Component)、指示(Directive)有

import { Injectable, OnInit } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class SvcService implements OnInit{

  constructor() {
    console.log('SvcService constructor')
  }

  ngOnInit() {
    console.log('SvcService ngOnInit')
  }
}

上一篇
# Day22 【牙起來】 非同步事件 第一支訂閱 - RxJS
下一篇
# Day24 【牙起來】 訂閱Subscribe、被訂閱者Observable - RxJS
系列文
Angular牙起來30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言